package com.flex.util.proxy {

   import com.flex.util.RemoteService;
   import com.flex.util.StringUtils;
   import com.flex.util.events.MethodReturnEvent;
   
   import flash.events.Event;
   
   import mx.core.FlexGlobals;
   import mx.logging.ILogger;
   import mx.rpc.AbstractOperation;
   import mx.rpc.events.FaultEvent;
   import mx.rpc.events.ResultEvent;

   public class BaseProxy {
      private var _service:*;
      private var _opInvoker:OperationInvoker;

      public function BaseProxy(serviceName:String, channelUri:String = null, secure:Object = null) {
         _service = RemoteService.getInstance(serviceName, secure);
         if (_service == null) {
            return;
         }

         if (! StringUtils.isNullorEmpty(channelUri)) {
            _service.serviceChannelUri = channelUri;
         }
         _opInvoker = new OperationInvoker();
      }

      public function set channelUri(channelUri:String):void {
         if (StringUtils.isNullorEmpty(channelUri)) {
            return;
         }
         _service.serviceChannelUri = channelUri;
      }

      public function callService(methodName:String, arguments:Array,
                                  callback:Function=null, callContext:Object=null):void {
         var operation:AbstractOperation = _service[methodName];
         var opContext:Object = {orgCallback : callback,
            orgCallContext : callContext};
         _opInvoker.invoke(operation, arguments, onInvocationComplete, opContext);
      }

      protected function result(
         event:ResultEvent,
         callback:Function,
         callContext:Object):void {
         if (callback == null || event == null) {
            return;
         }
         // Create ResultEvent and call the callback function
         var returnEvent:MethodReturnEvent =
            MethodReturnEvent.newResultEvent(event.result, callContext);
         notify(callback, returnEvent);
      }

      /**
       * Invokes the supplied callback with callContext and unpacked fault.
       */
      protected function fault(
         event:FaultEvent,
         callback:Function,
         callContext:Object):void {
         if (callback == null || event == null) {
            return;
         }
         // Create ErrorEvent and call the callback function
         var returnEvent:MethodReturnEvent =
            MethodReturnEvent.newErrorEvent(event.fault, callContext);
         notify(callback, returnEvent);
      }

      protected function notify(callback:Function, event:MethodReturnEvent):void {
         callback(event);
      }

      /**
       * Handles response of the invocation.
       */
      private function onInvocationComplete(event:Event, opContext:Object):void {
         var origCallback:Function = opContext.orgCallback;
         var origCallContext:Object = opContext.orgCallContext;
         if (event is ResultEvent) {
            result(event as ResultEvent,  origCallback, origCallContext);
         } else if (event is FaultEvent) {
            fault(event as FaultEvent,  origCallback, origCallContext);
         }
      }
   }
}